#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setFixedSize(width(),height());
    initPollFunc();
    initSlaveFunc();
}

Widget::~Widget()
{
    delete ui;
}


//初始化主站
void Widget::initPollFunc()
{
    ui->tableWidget_pTableWidget->setRowCount(10);
    ui->tableWidget_pTableWidget->setColumnCount(2);
    QStringList hList;
    hList << "Alias" << "00000";
    ui->tableWidget_pTableWidget->setHorizontalHeaderLabels(hList);

    QStringList vList;
    for(int i=0;i<10;i++)
    {
        vList << QString("%1").arg(i);
    }
    ui->tableWidget_pTableWidget->setVerticalHeaderLabels(vList);

    for(int i=0;i<10;i++)
    {
        ui->tableWidget_pTableWidget->setItem(i,0,new QTableWidgetItem(""));
        ui->tableWidget_pTableWidget->setItem(i,1,new QTableWidgetItem(""));
    }

    ui->comboBox_pType->addItem("SerialPort");
    ui->comboBox_pType->addItem("TCP");
    ui->lineEdit_pSAdr->setText("1");

}
//初始化从站
void Widget::initSlaveFunc()
{
    ui->tableWidget_sTableWidget->setRowCount(10);
    ui->tableWidget_sTableWidget->setColumnCount(2);
    QStringList hList;
    hList << "Alias" << "00000";
    ui->tableWidget_sTableWidget->setHorizontalHeaderLabels(hList);

    QStringList vList;
    for(int i=0;i<10;i++)
    {
        vList << QString("%1").arg(i);
    }
    ui->tableWidget_sTableWidget->setVerticalHeaderLabels(vList);

    for(int i=0;i<10;i++)
    {
        ui->tableWidget_sTableWidget->setItem(i,0,new QTableWidgetItem(""));
        ui->tableWidget_sTableWidget->setItem(i,1,new QTableWidgetItem(""));
    }

    ui->comboBox_sType->addItem("SerialPort");
    ui->comboBox_sType->addItem("TCP");
    ui->lineEdit_sSAdr->setText("1");

    //从站下拉框选项
    ui->comboBox_sTableType->addItem("Coils",QModbusDataUnit::Coils);
    ui->comboBox_sTableType->addItem("InputRegisters",QModbusDataUnit::InputRegisters);
    ui->comboBox_sTableType->addItem("DiscreteInputs",QModbusDataUnit::DiscreteInputs);
    ui->comboBox_sTableType->addItem("HoldingRegisters",QModbusDataUnit::HoldingRegisters);
}


void Widget::on_comboBox_pType_currentTextChanged(const QString &arg1)
{
    if(arg1 == "SerialPort")
    {
        ui->lineEdit_pIPorCom->setText("COM1");
        ui->lineEdit_pPort->setText("");
    }
    else if(arg1 == "TCP")
    {
        ui->lineEdit_pIPorCom->setText("127.0.0.1");
        ui->lineEdit_pPort->setText("4000");
    }
}

void Widget::on_comboBox_sType_currentTextChanged(const QString &arg1)
{
    if(arg1 == "SerialPort")
    {
        ui->lineEdit_sIporCom->setText("COM2");
        ui->lineEdit_sPort->setText("");
    }
    else if(arg1 == "TCP")
    {
        ui->lineEdit_sIporCom->setText("127.0.0.1");
        ui->lineEdit_sPort->setText("4000");
    }
}

void Widget::on_pushButton_pCon_clicked()
{
    if(ui->pushButton_pCon->text() == QString::fromUtf8("连接"))
    {
        qDebug() << QString::fromUtf8("进入了if(ui->pushButton_pCon->text() == 连接)");

        if(ui->comboBox_pType->currentText() == "SerialPort")//Modbus RTU模式
        {
            qDebug() << QString::fromUtf8("进入了if(ui->comboBox_pType->currentText() == SerialPort)");
            //创建主站对象
            master = new QModbusRtuSerialMaster();
            //串口名称
            master->setConnectionParameter(QModbusDevice::SerialPortNameParameter,ui->lineEdit_pIPorCom->text());
            //奇偶校验
            master->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::EvenParity);
            //波特率
            master->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,QSerialPort::Baud9600);
            //数据位
            master->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,QSerialPort::Data8);
            //停止位
            master->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneStop);
        }
        else//Modbus TCP模式
        {
            qDebug() << "进入了Modbus TCP模式 ";
            master = new QModbusTcpClient();

            //走的网络接口,设置IP和端口
            master->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ui->lineEdit_pIPorCom->text());
            master->setConnectionParameter(QModbusDevice::NetworkPortParameter,ui->lineEdit_pPort->text().toUInt());
            qDebug() << ui->lineEdit_pSAdr->text();
        }

        //连接超时1S
        master->setTimeout(1000);
        //如果超时，重试3次
        master->setNumberOfRetries(3);

        //设备状态改变时
        connect(master,&QModbusClient::stateChanged,this,[this](){
            if(master->state() == QModbusDevice::ConnectedState)
            {
                ui->pushButton_pCon->setText(QString::fromUtf8("断开"));
                QMessageBox::information(NULL,"成功","Connect Success!");
            }
            else
            {
                ui->pushButton_pCon->setText(QString::fromUtf8("连接"));

            }
        });

        //错误发生时
        connect(master,&QModbusClient::errorOccurred,[this](QModbusDevice::Error){
            QMessageBox::critical(NULL,"错误",master->errorString());
            ui->pushButton_pCon->setText("连接");
        });

        //连接设备
        master->connectDevice();


    }
    else
    {
        if(master)
        {
            //断开设备
            master->disconnectDevice();
            delete master;
            master = nullptr;
        }

    }
}


//RTU主站发送03功能码
//使用sendRawRequest发送QModbusRequest
//收到从站回复为QModbusResponse(QModbusResponse)
//void Widget::on_pushButton_p03_clicked()
//{
//    if(master == nullptr)
//    {
//        QMessageBox::critical(NULL,"错误",QString::fromUtf8("还没有建立主站和从站的连接!"));
//        return;
//    }

//    //功能码03读取多个保持寄存器，起始地址0000读取数量000A个
//    QModbusRequest mr(QModbusRequest::ReadHoldingRegisters,QByteArray::fromHex("0000000A"));

//    //发送指令给从站
//    if(QModbusReply *reply = master->sendRawRequest(mr,ui->lineEdit_pSAdr->text().toInt()))
//    {
//        //如果还没完成回复
//        if(!reply->isFinished())
//        {
//            connect(reply,&QModbusReply::finished,this,[this,reply](){
//                //无错误
//                if(reply->error() == QModbusDevice::NoError)
//                {
//                    //得到原始回复
//                    const QModbusResponse response = reply->rawResult();
//                    //得到功能码
//                    QModbusPdu::FunctionCode code = response.functionCode();
//                    //第1个字节表示数据长度
//                    int len = (int) response.data()[0];
//                    //数据、每个数据占2个字节
//                    for(int i=0;i<len/2;i++)
//                    {
//                        char high = response.data()[i*2+1];
//                        char low = response.data()[i*2+2];
//                        //得到寄存器的值，将两个字节（高字节和低字节）组合成一个16位无符号整数（quint16）
//                        quint16 v = (high<<8) | low;
//                        //设置到表格
//                        ui->tableWidget_pTableWidget->item(i,1)->setText(QString::number(v));
//                    }
//                }
//                else
//                {

//                    QMessageBox::critical(NULL,"错误",reply->errorString());
//                }

//                //通过事件循环去延迟删除对象
//                reply->deleteLater();
//            });
//        }
//    }
//    else
//    {
//         QMessageBox::critical(NULL,"错误",master->errorString());
//    }
//}


//RTU主站发送03功能码
//使用sendReadRequest发送QModbusDataUnit
//收到从站回复为QModbusResponse(QModbusDataUnit)
void Widget::on_pushButton_p03_clicked()
{
    if(master == nullptr)
    {
        QMessageBox::critical(NULL,"错误",QString::fromUtf8("还没有建立主站和从站的连接!"));
        return;
    }

    //保持寄存器类型，起始地址0、读取数量10个
    QModbusDataUnit mdu(QModbusDataUnit::HoldingRegisters,0,10);
    //读操作,提供QModbusDataUnit结构，会自动生成03功能报文格式
    if(QModbusReply *reply = master->sendReadRequest(mdu,ui->lineEdit_pSAdr->text().toInt()))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[this,reply](){
                if(reply->error() == QModbusDevice::NoError)
                {
                    //获取从站的应答数据
                    const QModbusDataUnit unit = reply->result();

                    for(int i=0;i<unit.valueCount();i++)
                    {
                        quint16 v = unit.value(i);//取得数据
                        ui->tableWidget_pTableWidget->item(unit.startAddress() + i,1)->setText(QString::number(v));
                    }
                }
                else
                {
                    QMessageBox::critical(NULL,"错误",reply->errorString());
                }
                //事件延迟删除
                reply->deleteLater();
            });
        }
    }
    else
    {
        QMessageBox::critical(NULL,"错误",master->errorString());
    }
}










//RTU主站发送06功能码
//使用sendReadRequest发送QModbusDataUnit
//收到从站回复为QModbusResponse(QModbusDataUnit)
//void Widget::on_pushButton_p06_clicked()
//{
//    if(master == nullptr)
//    {
//        QMessageBox::critical(NULL,"错误",QString::fromUtf8("还没有建立主站和从站的连接!"));
//        return;
//    }


//    QModbusRequest mr(QModbusPdu::WriteSingleRegister );
//    mr.setData(QByteArray::fromHex("0003033A"));

//    //向从站发送raw原始请求
//    if( QModbusReply *reply= master->sendRawRequest(mr, ui->lineEdit_pSAdr->text().toUInt()))
//    {

//        if(!reply->isFinished())
//        {

//            connect( reply, &QModbusReply::finished , this ,[this,reply]{
//                qDebug() << "connect(reply,&QModbusReply::finished,this,[this,reply](){";
//                if(reply->error() == QModbusDevice::NoError)
//                {
//                    qDebug() << "if(reply->error() == QModbusDevice::NoError)";
//                    const QModbusResponse result = reply->rawResult();
//                    QModbusPdu::FunctionCode  code = result.functionCode();
//                    QByteArray data = result.data();
//                    unsigned char high1 = data[0];
//                    unsigned char low1 = data[1];
//                    unsigned char high2 = data[2];
//                    unsigned char low2 = data[3];
//                    quint16 v1 = (high1<<8) | low1;//写入位置
//                    quint16 v2 = (high2<<8) | low2;//写入值
//                    ui->tableWidget_pTableWidget->item(v1,1)->setText(QString::number(v2));
//                }
//                else
//                {
//                    QMessageBox::critical(NULL,"错误",reply->errorString());
//                }
//                //事件延迟删除
//                reply->deleteLater();
//            });


//        }

//    }
//    else
//    {
//        QMessageBox::critical(NULL,"错误",master->errorString());
//    }


//}


void Widget::on_pushButton_p06_clicked()
{
    if(master == nullptr)
    {
        QMessageBox::critical(NULL,"错误",QString::fromUtf8("还没有建立主站和从站的连接!"));
        return;
    }
    //单个值
    QVector<quint16> vec;


    //自定义消息对话框,接收要写入的pos和value
    dialog06Btn = new Dialog06Btn;
    dialog06Btn->show();
    dialog06Btn->exec();//阻塞线程
    int pos = dialog06Btn->pos;
    QString valueStr = dialog06Btn->value;


    vec.push_back(valueStr.toUInt());

    //保持寄存器
    QModbusDataUnit mdu(QModbusDataUnit::HoldingRegisters,pos,vec);

    if(QModbusReply *reply = master->sendWriteRequest(mdu,ui->lineEdit_pSAdr->text().toUInt()))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[this,reply](){
                if(reply->error() == QModbusDevice::NoError)
                {
                    const QModbusDataUnit unit = reply->result();
                    quint16 v = unit.value(0);
                    ui->tableWidget_pTableWidget->item(unit.startAddress(),1)->setText(QString::number(v));
                }
                reply->deleteLater();
            });
        }
    }

    if(dialog06Btn)
    {
        delete dialog06Btn;
        dialog06Btn = nullptr;
    }

}



////RTU 16 功能码
//void Widget::on_pushButton_p16_clicked()
//{
//    QByteArray arr;
//    //起始位置
//    arr.push_back((char)0);
//    arr.push_back((char)0);
//    //写入数量
//    arr.push_back((char)0);
//    arr.push_back((char)10);
//    //数据大小
//    arr.push_back((char)20);
//    //数据值
//    for(int i=0;i<10;i++)
//    {
//        QString data = ui->tableWidget_pTableWidget->item(i,1)->text();
//        if(data.isEmpty())
//        {
//            data = "0";
//        }
//        quint16 v = data.toUInt();
//        char high = v >> 8;
//        char low = v;
//        arr.push_back(high);
//        arr.push_back(v);
//    }

//    //向主站发送请求
//    QModbusRequest mr(QModbusRequest::WriteMultipleRegisters,arr);
//    if(QModbusReply *reply = master->sendRawRequest(mr,ui->lineEdit_pSAdr->text().toUInt()))
//    {
//        if(!reply->isFinished())
//        {
//            connect(reply,&QModbusReply::finished,this,[this,reply](){
//                if(reply->error() == QModbusDevice::NoError)
//                {
//                   QMessageBox::information(NULL,"成功","WriteMultipleRegisters写入成功");
//                }
//                reply->deleteLater();
//            });

//        }
//    }
//}


//RTU 16 功能码
void Widget::on_pushButton_p16_clicked()
{
    if(master == nullptr)
    {
        QMessageBox::critical(NULL,"错误",QString::fromUtf8("还没有建立主站和从站的连接!"));
        return;
    }

    QVector<quint16> vec;
    for(int i=0;i<10;i++)
    {
        QString data = ui->tableWidget_pTableWidget->item(i,1)->text();
        if(data.isEmpty())
        {
            data = "0";
        }
        vec.push_back(data.toInt());
    }
    //保持寄存器，起始位置0，多个值
    QModbusDataUnit mdu(QModbusDataUnit::HoldingRegisters,0,vec);
    if(QModbusReply *reply = master->sendWriteRequest(mdu,ui->lineEdit_pSAdr->text().toUInt()))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[this,reply](){
                if(reply->error() == QModbusDevice::NoError)
                {
                    QMessageBox::information(NULL,"成功","sendWriteRequest写入成功");
                }
                else
                {
                    QMessageBox::critical(NULL,"失败","sendWriteRequest写入失败");
                }
            });
        }
    }
}



//从站连接
void Widget::on_pushButton_sCon_clicked()
{
    if(ui->pushButton_sCon->text() == QString::fromUtf8("连接"))
    {
        qDebug() << "1";

        if(ui->comboBox_sType->currentText() == "SerialPort")//Modbus RTU模式
        {
            qDebug() << "2";
            //创建主站对象
            slave = new QModbusRtuSerialSlave();
            //串口名称

            slave->setConnectionParameter(QModbusDevice::SerialPortNameParameter,ui->lineEdit_sIporCom->text());

            //奇偶校验
            slave->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::EvenParity);
            //波特率
            slave->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,QSerialPort::Baud9600);
            //数据位
            slave->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,QSerialPort::Data8);
            //停止位
            slave->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,QSerialPort::OneStop);
        }
        else//Modbus TCP模式
        {
            qDebug() << "3";
            slave = new QModbusTcpServer();

            //走的网络接口,设置IP和端口
            slave->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ui->lineEdit_sIporCom->text());
            slave->setConnectionParameter(QModbusDevice::NetworkPortParameter,ui->lineEdit_sPort->text().toUInt());
            qDebug() << ui->lineEdit_sSAdr->text();
            qDebug() << ui->lineEdit_sPort->text().toUInt();
        }

        qDebug() << "4";
        //设置从站地址
        slave->setServerAddress(ui->lineEdit_sSAdr->text().toUInt());
        //设备状态改变时
        connect(slave,&QModbusClient::stateChanged,this,[this](){
            if(slave->state() == QModbusDevice::ConnectedState)
            {
                ui->pushButton_sCon->setText(QString::fromUtf8("断开"));
                QMessageBox::information(NULL,"成功","Connect Success!");

                //设置从站的四张表
                QModbusDataUnitMap map;
                //在从站为线圈寄存器分配10个值的数据
                map.insert(QModbusDataUnit::Coils,QModbusDataUnit(QModbusDataUnit::Coils,0,10));
                map.insert(QModbusDataUnit::DiscreteInputs,QModbusDataUnit(QModbusDataUnit::DiscreteInputs,0,10));
                map.insert(QModbusDataUnit::InputRegisters,QModbusDataUnit(QModbusDataUnit::InputRegisters,0,10));
                map.insert(QModbusDataUnit::HoldingRegisters,QModbusDataUnit(QModbusDataUnit::HoldingRegisters,0,10));
                slave->setMap(map);
            }
            else
            {
                ui->pushButton_sCon->setText(QString::fromUtf8("连接"));

            }
        });

        //当客户端数据写入服务器时发出信号
        //address (起始地址):客户端写入的寄存器起始地址
        //size(数量):客户端请求中指定的要写入的寄存器数量
        connect(slave,&QModbusServer::dataWritten,this,[this](QModbusDataUnit::RegisterType table,int address,int size){
            //同步更新UI
            for(int i=0;i<size;i++)
            {
                quint16 v = 0;
                slave->data(table,address+i,&v);
                ui->tableWidget_sTableWidget->item(address+i,1)->setText(QString::number(v));
            }
        });

        qDebug() << "5";
        //错误发生时
        connect(slave,&QModbusClient::errorOccurred,[this](QModbusDevice::Error){
            QMessageBox::critical(NULL,"错误",slave->errorString());
            ui->pushButton_sCon->setText("连接");
        });

        //连接设备
        slave->connectDevice();

        qDebug() << "6";
    }
    else
    {
        if(slave)
        {
            //断开设备
            slave->disconnectDevice();
            delete slave;
            slave = nullptr;
        }

    }
}

//表格编辑框内容改变的时候产生的信号
void Widget::on_tableWidget_sTableWidget_cellChanged(int row, int column)
{
    //安全
    if(slave == nullptr)
    {
        return;
    }


    //获取从站表格数据
    QString data = ui->tableWidget_sTableWidget->item(row,column)->text();
    if(data.isEmpty())
    {
        data = "0";
    }


    //将改变的值写入从站对应表的数据中(根据表类型的下拉框选择，设置表)
    QModbusDataUnit::RegisterType registerType = (QModbusDataUnit::RegisterType)ui->comboBox_sTableType->currentData().toUInt();

    slave->setData(registerType,row,data.toUInt());

}


void Widget::on_comboBox_sTableType_currentIndexChanged(int index)
{
    //安全
    if(slave == nullptr)
    {
        return;
    }
    //拿到表类型
    QModbusDataUnit::RegisterType registerType = (QModbusDataUnit::RegisterType)ui->comboBox_sTableType->currentData().toUInt();

    for(int i = 0;i<10;i++)
    {
        QString data = ui->tableWidget_sTableWidget->item(i,1)->text();
        if(data.isEmpty())
        {
            data = "0";
        }
        slave->setData(registerType,i,data.toUInt());
    }

}
